
// Copyright (C) 2012 Luca Piccioni
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//  
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//  
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

using System;
using System.Diagnostics;

using Derm.OpenGL;

namespace Derm.Render
{
	/// <summary>
	/// Specify how polygons are rasterized.
	/// </summary>
	public sealed class PolygonModeState : RenderState
	{
		#region Constructors

		/// <summary>
		/// 
		/// </summary>
		public PolygonModeState()
		{
			
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="face"></param>
		/// <param name="mode"></param>
		public PolygonModeState(Face face, Mode mode)
		{
			FaceMode = face;
			RasterMode = mode;
		}

		public PolygonModeState(RenderContext ctx)
		{
			if (ctx == null)
				throw new ArgumentNullException("ctx");

			int face, mode;

			
		}

		#endregion

		#region Polygon Mode State Definition

		/// <summary>
		/// Equation that determine of source and destination fragments components are combined with each other.
		/// </summary>
		public enum Face
		{
			/// <summary>
			/// Front faces are rasterized.
			/// </summary>
			Front = Gl.FRONT,
			/// <summary>
			/// Back faces are rasterized.
			/// </summary>
			Back = Gl.BACK,
			/// <summary>
			/// Front and cack faces are rasterized.
			/// </summary>
			FrontAndBack = Gl.FRONT_AND_BACK,
		}

		/// <summary>
		/// Specify how polygon is rasterized.
		/// </summary>
		public enum Mode
		{
			/// <summary>
			/// Polygon is drawn with points.
			/// </summary>
			Point = Gl.POINT,
			/// <summary>
			/// Polygon is drawn with lines.
			/// </summary>
			Line = Gl.LINE,
			/// <summary>
			/// Polygon is filled.
			/// </summary>
			Fill = Gl.FILL,
		}

		/// <summary>
		/// Currently selected face mode.
		/// </summary>
		public Face FaceMode { get { return (mFaceMode); } set { mFaceMode = value; } }

		/// <summary>
		/// Specify how polygon is rasterized.
		/// </summary>
		public Mode RasterMode { get { return (mRasterMode); } set { mRasterMode = value; } }

		/// <summary>
		/// Currently selected face mode.
		/// </summary>
		private Face mFaceMode = Face.Front;

		/// <summary>
		/// Specify how polygon is rasterized.
		/// </summary>
		private Mode mRasterMode = Mode.Fill;

		#endregion

		#region Default State

		/// <summary>
		/// The system default state for BlendState.
		/// </summary>
		public static PolygonModeState DefaultState { get { return (new PolygonModeState()); } }

		#endregion

		#region RenderState Overrides

		/// <summary>
		/// The identifier for the blend state.
		/// </summary>
		public static string StateId = "GL.PolygonMode";

		/// <summary>
		/// The identifier of this RenderState.
		/// </summary>
		public override string Id { get { return (StateId); } }

		/// <summary>
		/// Flag indicating whether the state is context-bound.
		/// </summary>
		/// <remarks>
		/// It returns always true.
		/// </remarks>
		public override bool IsContextBound { get { return (true); } }

		/// <summary>
		/// Set ShaderProgram state.
		/// </summary>
		/// <param name="ctx">
		/// A <see cref="RenderContext"/> which has defined the shader program <paramref name="sProgram"/>.
		/// </param>
		/// <param name="sProgram">
		/// The <see cref="ShaderProgram"/> which has the state set.
		/// </param>
		public override void ApplyState(RenderContext ctx, ShaderProgram sProgram)
		{
			// Enable blending
			Gl.PolygonMode((int)FaceMode, (int)RasterMode);
			RenderException.DebugCheckErrors();
		}

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">
		/// A <see cref="RenderState"/> to compare to this RenderState.
		/// </param>
		/// <returns>
		/// It returns true if the current object is equal to <paramref name="other"/>.
		/// </returns>
		/// <remarks>
		/// <para>
		/// This method test only whether <paramref name="other"/> type equals to this type.
		/// </para>
		/// </remarks>
		/// <exception cref="ArgumentNullException">
		/// This exception is thrown if the parameter <paramref name="other"/> is null.
		/// </exception>
		public override bool Equals(IRenderState other)
		{
			if (base.Equals(other) == false)
				return (false);
			Debug.Assert(other is PolygonModeState);

			PolygonModeState otherState = (PolygonModeState) other;

			if (FaceMode != otherState.FaceMode)
				return (false);
			if (RasterMode != otherState.RasterMode)
				return (false);

			return (true);
		}

		/// <summary>
		/// Performs a deep copy of this <see cref="IRenderState"/>.
		/// </summary>
		/// <returns>
		/// It returns the equivalent of this <see cref="IRenderState"/>, but all objects referenced
		/// are not referred by both instances.
		/// </returns>
		public override IRenderState Copy()
		{
			return (new PolygonModeState(FaceMode, RasterMode));
		}
		
		#endregion
	}
}
